class JsonFormGenerator {
  constructor(options) {
    this.onSaveSuccess = options.onSaveSuccess || function () {}; 
    this.onSaveError = options.onSaveError || function () {};  
    this.container = document.querySelector(options.container);
    this.initialData = options.initialData || {};
    this.nonEditablePaths = options.nonEditablePaths || [];
    this.apiConfig = {
      url: options.apiUrl || '/api/save_order',
      method: options.apiMethod || 'POST',
      headers: options.apiHeaders || {
        'Content-Type': 'application/json',
      }
    };
    this.jsonData = JSON.parse(JSON.stringify(this.initialData));
    this.originalJsonData = JSON.parse(JSON.stringify(this.initialData));
    this.modifiedValues = new Map();
    this.searchKeyword = '';
    // 跟踪展开状态的映射表
    this.expandedState = new Map();
    this.detectAllModifiedValues();
    this.init();
  }

  // 新增：检查路径是否匹配（支持父子路径双向匹配）
  isPathIncluded(path) {
    if (!this.includeFields) return true;
    return this.includeFields.some(field => 
      path === field || 
      path.startsWith(field + '.') || 
      field.startsWith(path + '.')
    );
  }

  // 新增：检查路径是否被排除
  isPathExcluded(path) {
    return this.excludeFields.some(field => 
      path === field || path.startsWith(field + '.')
    );
  }
  
  detectAllModifiedValues() {
    this.modifiedValues.clear();
    this.compareValues(this.jsonData, this.originalJsonData, '');
  }

  compareValues(current, original, path) {
    if (original === undefined) {
      this.modifiedValues.set(path, { original: undefined, current, status: 'added' });
      return;
    }

    if (typeof current !== 'object' || current === null || typeof original !== 'object' || original === null) {
      if (current !== original) {
        this.modifiedValues.set(path, { original, current, status: 'modified' });
      } else if (this.modifiedValues.has(path)) {
        this.modifiedValues.delete(path);
      }
      return;
    }

    if (Array.isArray(current) && Array.isArray(original)) {
      if (current.length !== original.length) {
        for (let i = 0; i < current.length; i++) {
          const newPath = path ? `${path}[${i}]` : `[${i}]`;
          if (i >= original.length) {
            this.modifiedValues.set(newPath, { original: undefined, current: current[i], status: 'added' });
          } else {
            this.compareValues(current[i], original[i], newPath);
          }
        }
        for (let i = current.length; i < original.length; i++) {
          const newPath = path ? `${path}[${i}]` : `[${i}]`;
          if (!this.modifiedValues.has(newPath)) {
            this.modifiedValues.set(newPath, { original: original[i], current: undefined, status: 'deleted' });
          }
        }
      } else {
        current.forEach((item, index) => {
          const newPath = path ? `${path}[${index}]` : `[${index}]`;
          this.compareValues(item, original[index], newPath);
        });
      }
    } else if (!Array.isArray(current) && !Array.isArray(original)) {
      const currentKeys = Object.keys(current);
      const originalKeys = Object.keys(original);

      currentKeys.forEach(key => {
        if (!originalKeys.includes(key)) {
          const newPath = path ? `${path}.${key}` : key;
          this.modifiedValues.set(newPath, { original: undefined, current: current[key], status: 'added' });
        }
      });

      originalKeys.forEach(key => {
        if (currentKeys.includes(key)) {
          const newPath = path ? `${path}.${key}` : key;
          this.compareValues(current[key], original[key], newPath);
        } else {
          const newPath = path ? `${path}.${key}` : key;
          this.modifiedValues.set(newPath, { original: original[key], current: undefined, status: 'deleted' });
        }
      });
    } else {
      this.modifiedValues.set(path, { original, current, status: 'modified' });
    }
  }


  init() {
    this.injectStyles();
    this.renderHtmlStructure();
    this.bindEvents();
    // 默认展开根节点
    this.expandedState.set('', true);
    this.renderJsonTable(this.jsonData);
  }

  injectStyles() {
    const style = document.createElement('style');
    style.textContent = `
      .content-auto { content-visibility: auto; }
      .table-shadow { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); }
      .cell-hover { transition: all 0.2s ease; }
      .cell-hover:hover { background-color: rgba(59, 130, 246, 0.05); }
      .expand-icon { transition: transform 0.2s ease; display: inline-block; }
      .expand-icon.expanded { transform: rotate(90deg); }
      .editable-cell { position: relative; }
      .edit-overlay { position: absolute; inset: 0; background: white; display: flex; align-items: center; padding: 0 0.5rem; border-radius: 0.25rem; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5); z-index: 29891020; }
      .edit-input { flex: 1; border: 1px solid #ddd; border-radius: 0.25rem; padding: 0.25rem 0.5rem; outline: none; }
      .edit-textarea { flex: 1; border: 1px solid #ddd; border-radius: 0.25rem; padding: 0.25rem 0.5rem; outline: none; min-height: 80px; resize: vertical; }
      .edit-controls { display: flex; gap: 0.5rem; margin-left: 0.5rem; }
      .edit-btn { padding: 0.25rem 0.5rem; border-radius: 0.25rem; cursor: pointer; transition: all 0.2s ease; }
      .edit-save { background-color: #3B82F6; color: white; }
      .edit-save:hover { background-color: #2563EB; }
      .edit-cancel { background-color: #E5E7EB; color: #4B5563; }
      .edit-cancel:hover { background-color: #D1D5DB; }
      .editing { background-color: rgba(59, 130, 246, 0.05); }
      .modified-value { color: #EF4444; position: relative; }
      .modified-value::after { content: '●'; position: absolute; top: -0.5rem; right: -0.5rem; font-size: 0.6rem; color: #EF4444; }
      .non-editable { background-color: #e5e1e2; cursor: not-allowed !important; }
      .tooltip { position: absolute; background-color: #333; color: white; padding: 0.5rem; border-radius: 0.25rem; font-size: 0.8rem; z-index: 29891020; opacity: 0; transition: opacity 0.2s ease; pointer-events: none; max-width: 300px; word-wrap: break-word; }
      .tooltip-visible { opacity: 1; }
      .add-button, #add-root-key { opacity: 0; transition: opacity 0.2s ease; }
      .cell-hover:hover .add-button, #add-root-key:hover { opacity: 1; }
      .delete-button { opacity: 0; transition: opacity 0.2s ease; }
      .cell-hover:hover .delete-button { opacity: 1; }
      .add-overlay, .delete-confirmation, .save-confirmation, .api-message { 
        position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); 
        background: white; display: flex; flex-direction: column; align-items: center; 
        padding: 1rem; border-radius: 0.5rem; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); 
        min-width: 300px; max-width: 90%; max-height: 80vh; overflow-y: auto; 
        z-index: 29891020 !important;
      }
      .api-message {
        min-width: 350px;
        text-align: center;
      }
      .api-message.success { border-top: 4px solid #10B981; }
      .api-message.error { border-top: 4px solid #EF4444; }
      .add-input { width: 100%; border: 1px solid #ddd; border-radius: 0.25rem; padding: 0.5rem; outline: none; margin-bottom: 0.5rem; }
      .delete-confirmation { color: #EF4444; }
      .success-animation { animation: success-pulse 1s ease-in-out; }
      .delete-animation { animation: delete-pulse 0.5s ease-in-out; }
      @keyframes success-pulse { 0% { background-color: rgba(16, 185, 129, 0); } 50% { background-color: rgba(16, 185, 129, 0.2); } 100% { background-color: rgba(16, 185, 129, 0); } }
      @keyframes delete-pulse { 0% { background-color: rgba(239, 68, 68, 0); } 50% { background-color: rgba(239, 68, 68, 0.2); } 100% { background-color: rgba(239, 68, 68, 0); } }
      .overlay-backdrop { position: fixed; inset: 0; background-color: rgba(0, 0, 0, 0.3); z-index: 29891020; backdrop-filter: blur(2px); }
      .search-container { margin-bottom: 1rem; padding: 0 1rem; }
      .search-input { width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 0.25rem; font-size: 0.9rem; }
      .search-input:focus { outline: none; border-color: #3B82F6; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); }
      .search-results { color: #666; font-size: 0.8rem; margin-top: 0.5rem; text-align: right; }
      .save-confirmation h3 { margin-top: 0; color: #333; }
      .changes-table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
      .changes-table th, .changes-table td { border: 1px solid #ddd; padding: 0.75rem; text-align: left; }
      .changes-table th { background-color: #f3f4f6; font-weight: 600; }
      .changes-table .path-cell { 
        max-width: 200px; 
        overflow: hidden; 
        text-overflow: ellipsis; 
        white-space: nowrap; 
        position: relative; 
      }
      .changes-table .path-cell:hover { 
        overflow: visible; 
        white-space: normal; 
        z-index: 29891020; 
        background: white; 
        box-shadow: 0 2px 8px rgba(0,0,0,0.1); 
      }
      .changes-table .value-cell { 
        max-width: 250px; 
        white-space: pre-wrap; 
        word-wrap: break-word; 
        font-family: monospace;
        font-size: 0.85rem;
        line-height: 1.4;
      }
      .changes-table th, .changes-table td {
        white-space: nowrap; /* 强制不换行 */
        padding: 0.75rem 1rem; /* 增加一些内边距 */
      }

      .changes-table .path-cell, 
      .changes-table .status-cell {
        white-space: nowrap; /* 特定列不换行 */
        min-width: 120px; /* 设置最小宽度 */
      }

      .changes-table .value-cell {
        white-space: pre-wrap; /* 值单元格允许换行 */
      }
      .status-added { color: #10B981; background-color: rgba(16, 185, 129, 0.1); padding: 0.25rem 0.5rem; border-radius: 0.25rem; font-size: 0.8rem; }
      .status-modified { color: #F59E0B; background-color: rgba(245, 158, 11, 0.1); padding: 0.25rem 0.5rem; border-radius: 0.25rem; font-size: 0.8rem; }
      .status-deleted { color: #EF4444; background-color: rgba(239, 68, 68, 0.1); padding: 0.25rem 0.5rem; border-radius: 0.25rem; font-size: 0.8rem; }
      .no-changes { padding: 1rem; text-align: center; color: #6B7280; }
      button { border: none; background: none; cursor: pointer; }
      .btn-primary { background-color: #3B82F6; color: white; }
      .btn-primary:hover { background-color: #2563EB; }
      .btn-success { background-color: #10B981; color: white; }
      .btn-success:hover { background-color: #059669; }
      .btn-danger { background-color: #EF4444; color: white; }
      .btn-danger:hover { background-color: #DC2626; }
      .btn-gray { background-color: #E5E7EB; color: #4B5563; }
      .btn-gray:hover { background-color: #D1D5DB; }
      .api-response {
        background-color: #f8fafc;
        border-radius: 0.375rem;
        padding: 1rem;
        margin: 1rem 0;
        width: 100%;
        text-align: left;
        font-family: monospace;
        font-size: 0.85rem;
        max-height: 200px;
        overflow-y: auto;
        white-space: pre-wrap;
        word-wrap: break-word;
      }
      /* 折叠相关样式 */
      .node-collapsed {
        display: none;
      }
      
    `;
    document.head.appendChild(style);
  }

  renderHtmlStructure() {
    this.container.innerHTML = `
      <div class="mb-8">
        <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-neutral">订单数据编辑页</h1>
      </div>
      <div class="search-container">
        <input type="text" id="json-search" class="search-input" placeholder="搜索字段名或值...">
        <div id="search-results" class="search-results"></div>
      </div>
      <div class="bg-white rounded-xl p-4 mb-6 table-shadow">
        <div class="flex items-center gap-3">
          <button id="expand-all" class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-all flex items-center gap-2">
            <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path></svg>
            <span>全部展开</span>
          </button>
          <button id="collapse-all" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-all flex items-center gap-2">
            <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 13l-7 7m0 0l-7-7m7 7V4"></path></svg>
            <span>全部折叠</span>
          </button>
          <button id="save-config" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-all flex items-center gap-2">
            <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
            <span>保存配置</span>
          </button>
        </div>
      </div>
      <div class="bg-white rounded-xl overflow-hidden table-shadow">
        <div class="overflow-x-auto">
          <table class="w-full">
            <thead>
              <tr class="bg-neutral-light">
                <th class="px-6 py-4 text-left text-sm font-semibold text-gray-700 tracking-wider">
                  字段名
                  <button id="add-root-key" class="ml-2 text-success add-button inline-flex items-center">
                    <svg class="h-4 w-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
                    <span>添加根节点</span>
                  </button>
                </th>
                <th class="px-6 py-4 text-left text-sm font-semibold text-gray-700 tracking-wider">值</th>
              </tr>
            </thead>
            <tbody id="json-table-body"></tbody>
          </table>
        </div>
      </div>
      <div id="value-tooltip" class="tooltip"><div class="font-medium">修改历史</div><div class="text-xs text-gray-300">原始值: <span id="original-value"></span></div><div class="text-xs text-gray-300">当前值: <span id="current-value"></span></div></div>
      <div id="overlay-backdrop" class="overlay-backdrop" style="display: none;"></div>
    `;
  }

  bindEvents() {
    // 修复展开全部按钮事件
    document.getElementById('expand-all').addEventListener('click', () => {
      this.expandAll();
    });
    
    // 修复折叠全部按钮事件
    document.getElementById('collapse-all').addEventListener('click', () => {
      this.collapseAll();
    });
    
    document.getElementById('add-root-key').addEventListener('click', () => this.startAdding(null, '', false));
    document.getElementById('overlay-backdrop').addEventListener('click', () => {
      this.hideTooltip();
      const addOverlay = document.querySelector('.add-overlay');
      const deleteConfirmation = document.querySelector('.delete-confirmation');
      const saveConfirmation = document.querySelector('.save-confirmation');
      const apiMessage = document.querySelector('.api-message');
      if (addOverlay) addOverlay.remove();
      if (deleteConfirmation) deleteConfirmation.remove();
      if (saveConfirmation) saveConfirmation.remove();
      if (apiMessage) apiMessage.remove();
      document.getElementById('overlay-backdrop').style.display = 'none';
    });
    
    document.getElementById('save-config').addEventListener('click', () => this.showSaveConfirmation());
    
    const searchInput = document.getElementById('json-search');
    searchInput.addEventListener('input', (e) => {
      this.searchKeyword = e.target.value.toLowerCase().trim();
      this.renderJsonTable(this.jsonData);
    });
  }

  showSaveConfirmation() {
    this.detectAllModifiedValues();
    
    document.getElementById('overlay-backdrop').style.display = 'block';
    
    const overlay = document.createElement('div');
    overlay.className = 'save-confirmation';
    overlay.style.zIndex = '29891020';  // 确保高于遮罩层
    
    if (this.modifiedValues.size === 0) {
      overlay.innerHTML = `
        <h3>保存配置</h3>
        <div class="no-changes">没有检测到任何修改</div>
        <div class="edit-controls">
          <button class="edit-btn edit-cancel" id="close-save">关闭</button>
        </div>
      `;
    } else {
      let changesHtml = `
        <h3>保存配置</h3>
        <p>以下是所有修改，确认保存吗？</p>
        <div style="overflow-x: auto; width: 100%;">
          <table class="changes-table">
            <thead>
              <tr>
                <th class="status-cell">字段路径</th>
                <th>原始值</th>
                <th>当前值</th>
                <th class="status-cell">状态</th>
              </tr>
            </thead>
            <tbody>
            
      `;
      
      this.modifiedValues.forEach((data, path) => {
        const statusClass = `status-${data.status}`;
        const statusText = data.status === 'added' ? '增加' : 
                          data.status === 'modified' ? '修改' : '删除';
        
        changesHtml += `
          <tr>
            <td class="path-cell" title="${path}">${path}</td>
            <td class="value-cell">${this.formatValue(data.original)}</td>
            <td class="value-cell">${this.formatValue(data.current)}</td>
            <td class="status-cell"><span class="${statusClass}">${statusText}</span></td>
          </tr>
        `;
      });
      
      changesHtml += `
            </tbody>
          </table>
        </div>
        <div class="edit-controls">
          <button class="edit-btn edit-save btn-success" id="confirm-save">是</button>
          <button class="edit-btn edit-cancel btn-gray" id="cancel-save">否</button>
        </div>
      `;
      
      overlay.innerHTML = changesHtml;
    }
    
    document.body.appendChild(overlay);
    
     // 修复事件监听器
    if (this.modifiedValues.size > 0) {
      overlay.querySelector('#confirm-save').addEventListener('click', () => {
        this.submitToApi();
        overlay.remove();
        document.getElementById('overlay-backdrop').style.display = 'none';
      });
      
      overlay.querySelector('#cancel-save').addEventListener('click', () => {
        overlay.remove();
        document.getElementById('overlay-backdrop').style.display = 'none';
      });
    } else {
      overlay.querySelector('#close-save').addEventListener('click', () => {
        overlay.remove();
        document.getElementById('overlay-backdrop').style.display = 'none';
      });
    }
  }
  
  async submitToApi() {
    try {
      this.showApiMessage('提交中...', 'loading');
      
      const payload = {
        data: this.jsonData,
      };
      
      const response = await fetch(this.apiConfig.url, {
        method: this.apiConfig.method,
        headers: this.apiConfig.headers,
        body: JSON.stringify(payload)
      });
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      const result = await response.json();
      
      this.showApiMessage('配置已成功保存', 'success');
      
      this.originalJsonData = JSON.parse(JSON.stringify(this.jsonData));
      this.modifiedValues.clear();
      this.renderJsonTable(this.jsonData);
      // 调用成功回调，可把 result 等数据传出去
      this.onSaveSuccess(result); 
      
    } catch (error) {
      this.showApiMessage('保存失败，请重试', 'error');
      // 调用失败回调，把错误信息传出去
      this.onSaveError(error);
    }
  } 

 showApiMessage(message, type) {
    // 移除已存在的旧提示窗口
    const oldMessage = document.querySelector('.api-message');
    if (oldMessage) {
        oldMessage.remove();
    }

    // 创建提示窗口容器
    const messageEl = document.createElement('div');
    messageEl.className = `api-message api-message-${type}`;
    messageEl.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: white;
        padding: 1.5rem 2.5rem;
        border-radius: 8px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        z-index: 29891020;
        text-align: center;
        font-size: 1rem;
        color: #333;
        opacity: 0;
        transition: all 0.3s ease;
    `;

    // 根据类型设置不同的边框顶部颜色和图标（可选，也可纯文字区分）
    const iconAndText = document.createElement('div');
    iconAndText.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
    `;
    let iconHtml = '';
    if (type === 'success') {
        iconHtml = '<svg class="h-5 w-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>';
        messageEl.style.borderTop = '4px solid #28a745'; // 绿色顶部边框
    } else if (type === 'error') {
        iconHtml = '<svg class="h-5 w-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>';
        messageEl.style.borderTop = '4px solid #dc3545'; // 红色顶部边框
    } else if (type === 'loading') {
        iconHtml = '<svg class="h-5 w-5 text-blue-500 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke-width="4"></circle><path class="opacity-75" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M4 12h16l-4 4-4-4z"></path></svg>';
        messageEl.style.borderTop = '4px solid #007bff'; // 蓝色顶部边框
    }
    iconAndText.innerHTML = iconHtml + message;

    messageEl.appendChild(iconAndText);

    // 添加到页面
    document.body.appendChild(messageEl);

    // 渐显动画
    setTimeout(() => {
        messageEl.style.opacity = 1;
    }, 30);

    // 自动关闭逻辑
    let timeout = 1000; // 成功提示默认3秒关闭
    if (type === 'error') {
        timeout = 4000; // 错误提示稍长
    } else if (type === 'loading') {
        timeout = Infinity; // 加载中不自动关闭（需手动移除）
    }

    if (timeout !== Infinity) {
        setTimeout(() => {
            if (messageEl.parentNode) { // 防止重复移除报错
                // 渐隐动画
                messageEl.style.opacity = 0;
                setTimeout(() => messageEl.remove(), 300);
            }
        }, timeout);
    }

    // 返回实例方便手动控制（如加载完成后关闭）
    return {
        close: () => {
            messageEl.style.opacity = 0;
            setTimeout(() => messageEl.remove(), 300);
        }
    };
}

  isMatchSearch(key, value, path) {
    if (!this.searchKeyword) return true;
    
    if (key.toLowerCase().includes(this.searchKeyword)) return true;
    
    if (typeof value === 'string' && value.toLowerCase().includes(this.searchKeyword)) return true;
    if (typeof value !== 'object' && value !== null) {
      return String(value).toLowerCase().includes(this.searchKeyword);
    }
    
    if (path.toLowerCase().includes(this.searchKeyword)) return true;
    
    return false;
  }

  countMatchingNodes(json, parentKey = '', countAll = false) {
    if (countAll) {
      let count = 0;
      if (Array.isArray(json)) {
        json.forEach((item, index) => {
          count++;
          if (typeof item === 'object' && item !== null) {
            count += this.countMatchingNodes(item, `${parentKey}[${index}]`, true);
          }
        });
      } else if (typeof json === 'object' && json !== null) {
        Object.keys(json).forEach(key => {
          count++;
          const fullKey = parentKey ? `${parentKey}.${key}` : key;
          if (typeof json[key] === 'object' && json[key] !== null) {
            count += this.countMatchingNodes(json[key], fullKey, true);
          }
        });
      } else {
        count++;
      }
      return count;
    } else {
      return this._countMatchingNodesInternal(json, parentKey);
    }
  }

  _countMatchingNodesInternal(json, parentKey = '') {
    let count = 0;
    
    if (Array.isArray(json)) {
      json.forEach((item, index) => {
        const key = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
        if (this.isMatchSearch(String(index), item, key)) {
          count++;
        }
        if (typeof item === 'object' && item !== null) {
          count += this._countMatchingNodesInternal(item, key);
        }
      });
    } else if (typeof json === 'object' && json !== null) {
      Object.keys(json).forEach(key => {
        const value = json[key];
        const fullKey = parentKey ? `${parentKey}.${key}` : key;
        if (this.isMatchSearch(key, value, fullKey)) {
          count++;
        }
        if (typeof value === 'object' && value !== null) {
          count += this._countMatchingNodesInternal(value, fullKey);
        }
      });
    } else {
      if (this.isMatchSearch(parentKey, json, parentKey)) {
        count++;
      }
    }
    
    return count;
  }

  renderJsonTable(json, parentKey = '', depth = 0) {
    const tableBody = document.getElementById('json-table-body');
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

    if (depth === 0) {
      tableBody.innerHTML = '';
      this.detectAllModifiedValues();
      
      const matchCount = this.countMatchingNodes(json);
      const totalCount = this.countMatchingNodes(json, '', true);
      document.getElementById('search-results').textContent = 
        this.searchKeyword ? `${matchCount} 个匹配结果（共 ${totalCount} 个节点）` : '';
    }

    // 检查当前节点是否应该显示
    const isExpanded = this.expandedState.has(parentKey) ? this.expandedState.get(parentKey) : true;
    if (!isExpanded && depth > 0) {
      return;
    }

    if (Array.isArray(json)) {
      json.forEach((item, index) => {
        const key = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
        if (!this.isMatchSearch(String(index), item, key) && 
            !(typeof item === 'object' && item !== null && this.countMatchingNodes(item, key) > 0)) {
          return;
        }
        
        const row = this.createRow(String(index), '', depth, true, item, key);
        tableBody.appendChild(row);
        this.renderJsonTable(item, key, depth + 1);
      });
    } else if (typeof json === 'object' && json !== null) {
      Object.keys(json).forEach(key => {
        const value = json[key];
        const isObject = typeof value === 'object' && value !== null;
        const fullKey = parentKey ? `${parentKey}.${key}` : key;
        
        if (!this.isMatchSearch(key, value, fullKey) && 
            !(isObject && this.countMatchingNodes(value, fullKey) > 0)) {
          return;
        }
        
        const row = this.createRow(key, isObject ? '' : this.formatValue(value), depth, isObject, value, fullKey);
        tableBody.appendChild(row);
        if (isObject) this.renderJsonTable(value, fullKey, depth + 1);
      });
    } else {
      if (!this.isMatchSearch(parentKey, json, parentKey)) {
        return;
      }
      
      const row = this.createRow(parentKey, this.formatValue(json), depth, false, json, parentKey);
      tableBody.appendChild(row);
    }

    if (depth === 0) {
      setTimeout(() => {
        document.documentElement.scrollTop = document.body.scrollTop = scrollTop;
      }, 0);
    }
  }

  createRow(key, value, depth, hasChildren, originalValue, fullKey) {
    const row = document.createElement('tr');
    row.className = 'border-b border-gray-100 cell-hover';
    row.dataset.level = depth;
    row.dataset.path = fullKey;

    const keyCell = document.createElement('td');
    keyCell.className = 'px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900';

    const indent = document.createElement('div');
    indent.className = `pl-[${depth * 1.5}rem] flex items-center gap-2`;

    if (hasChildren) {
        const expandButton = document.createElement('button');
        expandButton.className = 'expand-button p-1 rounded-full hover:bg-gray-100 transition-all';
        
        // 根据状态设置图标初始状态
        const isExpanded = this.expandedState.has(fullKey) ? this.expandedState.get(fullKey) : true;
        expandButton.innerHTML = `<svg class="expand-icon ${isExpanded ? 'expanded' : ''} h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>`;
        
        // 修复展开/折叠按钮事件
        expandButton.addEventListener('click', (e) => {
            e.stopPropagation();
            this.toggleRow(fullKey);
        });
        
        indent.appendChild(expandButton);
    } else {
        indent.appendChild(document.createElement('span')).className = 'w-5 h-5';
    }

    const keySpan = document.createElement('span');
    keySpan.innerHTML = this.highlightMatch(key, this.searchKeyword);
    indent.appendChild(keySpan);

    const isNonEditable = this.isNonEditableField(fullKey);
    const canDelete = depth > 0 || (depth === 0 && Object.keys(this.jsonData).length > 0);

    if (!isNonEditable) {
        if (hasChildren || depth === 0) {
            const addButton = document.createElement('button');
            addButton.className = 'ml-2 text-success add-button';
            addButton.innerHTML = `<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>`;
            addButton.addEventListener('click', (e) => { 
                e.stopPropagation(); 
                this.startAdding(row, fullKey, Array.isArray(this.getValueByPath(this.jsonData, fullKey))); 
            });
            indent.appendChild(addButton);
        }

        if (canDelete) {
            const deleteButton = document.createElement('button');
            deleteButton.className = 'ml-2 text-danger delete-button';
            deleteButton.innerHTML = `<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>`;
            deleteButton.addEventListener('click', (e) => { e.stopPropagation(); this.startDeleting(row, fullKey); });
            indent.appendChild(deleteButton);
        }
    }

    keyCell.appendChild(indent);

    const valueCell = document.createElement('td');
    valueCell.className = 'px-6 py-3 text-sm text-gray-500 editable-cell';
    valueCell.dataset.path = fullKey;

    const valueSpan = document.createElement('span');
    valueSpan.innerHTML = this.highlightMatch(value, this.searchKeyword);

    const isModified = this.modifiedValues.has(fullKey);
    
    if (isModified) {
        valueSpan.addEventListener('mouseenter', (e) => this.showTooltip(e, fullKey));
        valueSpan.addEventListener('mouseleave', () => this.hideTooltip());
    }

    if (isNonEditable) {
        valueSpan.className = 'cursor-not-allowed non-editable px-1 rounded';
    } else if (isModified) {
        valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded modified-value';
    } else {
        valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded';
    }

    if (!isNonEditable && !hasChildren) {
        valueSpan.addEventListener('click', (e) => { 
            e.stopPropagation(); 
            this.startEditing(valueCell, value, typeof originalValue === 'string' && value.includes('\n')); 
        });
    }

    valueCell.appendChild(valueSpan);
    row.appendChild(keyCell);
    row.appendChild(valueCell);

    // 允许点击行展开/折叠
    if (hasChildren) {
        row.addEventListener('click', () => this.toggleRow(fullKey));
    }

    return row;
}

  highlightMatch(text, keyword) {
    if (!keyword || !text) return text;
    const regex = new RegExp(`(${keyword})`, 'gi');
    return text.toString().replace(regex, '<span style="background-color: #FFF3CD; color: #D97706; border-radius: 2px;">$1</span>');
  }

  isNonEditableField(path) {
    return this.nonEditablePaths.includes(path);
  }

  formatValue(value) {
    if (value === null) return 'null';
    if (value === undefined) return 'undefined';
    if (typeof value === 'string' && value.trim() === '') return '[空]'; // 空字符串显示占位符
    if (typeof value === 'boolean') return value ? 'true' : 'false';
    if (typeof value === 'object') {
        // 检查是否为空对象
        if (value !== null && Object.keys(value).length === 0) {
            return '[对象]';
        }
        try {
            return JSON.stringify(value, null, 2);
        } catch (e) {
            return `[Object]`;
        }
    }
    return String(value);
}

  startEditing(cell, currentValue, isMultiline) {
    const existingOverlay = document.querySelector('.edit-overlay');
    if (existingOverlay) existingOverlay.remove();

    const path = cell.dataset.path;
    const actualValue = this.getValueByPath(this.jsonData, path);
    currentValue = actualValue;

    const overlay = document.createElement('div');
    overlay.className = 'edit-overlay';

    let input;
    if (isMultiline) {
        input = document.createElement('textarea');
        input.className = 'edit-textarea';
        input.value = currentValue !== undefined ? currentValue : '';
    } else {
        input = document.createElement('input');
        input.className = 'edit-input';
        input.type = 'text';
        input.value = currentValue !== undefined ? currentValue : '';
    }

    const controls = document.createElement('div');
    controls.className = 'edit-controls';

    const saveBtn = document.createElement('button');
    saveBtn.className = 'edit-btn edit-save';
    saveBtn.textContent = '保存';
    saveBtn.addEventListener('click', () => this.finishEditing(cell, input.value));

    const cancelBtn = document.createElement('button');
    cancelBtn.className = 'edit-btn edit-cancel';
    cancelBtn.textContent = '取消';
    cancelBtn.addEventListener('click', () => this.finishEditing(cell, '', true));

    controls.appendChild(saveBtn);
    controls.appendChild(cancelBtn);

    overlay.appendChild(input);
    overlay.appendChild(controls);
    cell.appendChild(overlay);

    input.focus();

    input.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        this.finishEditing(cell, input.value);
      } else if (e.key === 'Escape') {
        this.finishEditing(cell, '', true);
      }
    });
  }

  finishEditing(cell, newValue, isCancel = false) {
    const overlay = cell.querySelector('.edit-overlay');
    if (overlay) overlay.remove();

    if (isCancel) return;

    const path = cell.dataset.path;
    const oldValue = this.getValueByPath(this.jsonData, path);
    const parsedValue = this.parseValue(newValue);
    const originalValue = this.getValueByPath(this.originalJsonData, path);
    const valueSpan = cell.querySelector('span');

    const handleMouseEnter = (e) => this.showTooltip(e, path);
    const handleMouseLeave = () => this.hideTooltip();

    if (JSON.stringify(parsedValue) !== JSON.stringify(oldValue)) {
        this.updateJsonValue(path, parsedValue);
        valueSpan.textContent = this.formatValue(parsedValue);

        if (parsedValue !== originalValue) {
            valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded modified-value';
            this.modifiedValues.set(path, { original: originalValue, current: parsedValue, status: 'modified' });
            valueSpan.addEventListener('mouseenter', handleMouseEnter);
            valueSpan.addEventListener('mouseleave', handleMouseLeave);
        } else {
            valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded';
            this.modifiedValues.delete(path);
            valueSpan.removeEventListener('mouseenter', handleMouseEnter);
            valueSpan.removeEventListener('mouseleave', handleMouseLeave);
        }

        cell.classList.add('success-animation');
        setTimeout(() => cell.classList.remove('success-animation'), 1000);
    } else {
        if (oldValue !== originalValue) {
            valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded modified-value';
            this.modifiedValues.set(path, { original: originalValue, current: oldValue, status: 'modified' });
            valueSpan.addEventListener('mouseenter', handleMouseEnter);
            valueSpan.addEventListener('mouseleave', handleMouseLeave);
        } else {
            valueSpan.className = 'cursor-pointer hover:bg-blue-50 px-1 rounded';
            this.modifiedValues.delete(path);
            valueSpan.removeEventListener('mouseenter', handleMouseEnter);
            valueSpan.removeEventListener('mouseleave', handleMouseLeave);
        }
    }
  }

  startAdding(row, parentPath, isArray) {
    document.getElementById('overlay-backdrop').style.display = 'block';

    const overlay = document.createElement('div');
    overlay.className = 'add-overlay';
    overlay.style.zIndex = '100';  // 确保高于遮罩层

    overlay.innerHTML = `
      <h3>${isArray ? '添加数组元素' : '添加字段'}</h3>
      ${!isArray ? '<input type="text" class="add-input" placeholder="输入字段名" id="add-key-input">' : ''}
      <input type="text" class="add-input" placeholder="输入值（增加节点输入{}）" id="add-value-input">
      <div class="edit-controls">
        <button class="edit-btn edit-save btn-success" id="confirm-add">确认</button>
        <button class="edit-btn edit-cancel btn-gray" id="cancel-add">取消</button>
      </div>
    `;
    document.body.appendChild(overlay);

    overlay.querySelector('#confirm-add').addEventListener('click', () => {
      const key = !isArray ? overlay.querySelector('#add-key-input').value.trim() : null;
      const value = overlay.querySelector('#add-value-input').value.trim();
      
      if ((!isArray && !key) || value === '') return;
      
      this.addValue(parentPath, key, this.parseValue(value), isArray);
      overlay.remove();
      document.getElementById('overlay-backdrop').style.display = 'none';
    });

    overlay.querySelector('#cancel-add').addEventListener('click', () => {
      overlay.remove();
      document.getElementById('overlay-backdrop').style.display = 'none';
    });
  }

  getValueByPath(obj, path) {
    return path.split(/[\.\[\]]/g)
      .filter(part => part)
      .reduce((acc, part) => acc && acc[part], obj);
  }

  updateJsonValue(path, value) {
    const parts = path.split(/[\.\[\]]/g).filter(part => part);
    let current = this.jsonData;
    
    for (let i = 0; i < parts.length - 1; i++) {
      current = current[parts[i]];
    }
    
    current[parts[parts.length - 1]] = value;
  }

  parseValue(value) {
    if (value === '') return '';
    if (value === 'true') return true;
    if (value === 'false') return false;
    if (value === 'null') return null;
    
    if (value.startsWith('{') && value.endsWith('}')) {
      try {
        const obj = JSON.parse(value);
        if (typeof obj === 'object' && obj !== null) {
          return obj;
        }
      } catch (e) {
        // 解析失败，视为普通字符串
      }
    }
    
    if (!isNaN(Number(value))) return Number(value);
    return value;
  }

  addValue(parentPath, key, value, isArray) {
    const parent = parentPath ? this.getValueByPath(this.jsonData, parentPath) : this.jsonData;
    
    if (isArray && Array.isArray(parent)) {
      parent.push(value);
    } else if (typeof parent === 'object' && parent !== null) {
      parent[key] = value;
      const fullPath = parentPath ? `${parentPath}.${key}` : key;
      this.modifiedValues.set(fullPath, {
        original: null,
        current: value,
        type: 'added',
        status: 'added'
      });
      // 新添加的节点默认展开
      this.expandedState.set(fullPath, true);
    }
    
    this.renderJsonTable(this.jsonData);
  }

  startDeleting(row, path) {
    document.getElementById('overlay-backdrop').style.display = 'block';

    const overlay = document.createElement('div');
    overlay.className = 'delete-confirmation';
    overlay.style.zIndex = '100';  // 确保高于遮罩层
    overlay.innerHTML = `
      <h3>确认删除</h3>
      <p>确定要删除这个字段吗？</p>
      <div class="edit-controls">
        <button class="edit-btn edit-save btn-danger" id="confirm-delete">确认</button>
        <button class="edit-btn edit-cancel btn-gray" id="cancel-delete">取消</button>
      </div>
    `;
    document.body.appendChild(overlay);

    overlay.querySelector('#confirm-delete').addEventListener('click', () => {
      this.deleteValue(path);
      row.classList.add('delete-animation');
      setTimeout(() => {
        this.renderJsonTable(this.jsonData);
      }, 500);
      overlay.remove();
      document.getElementById('overlay-backdrop').style.display = 'none';
    });

    overlay.querySelector('#cancel-delete').addEventListener('click', () => {
      overlay.remove();
      document.getElementById('overlay-backdrop').style.display = 'none';
    });
  }

  deleteValue(path) {
    const parts = path.split(/[\.\[\]]/g).filter(part => part);
    const parentPath = parts.slice(0, -1).join('.');
    const key = parts[parts.length - 1];
    
    const parent = parentPath ? this.getValueByPath(this.jsonData, parentPath) : this.jsonData;
    
    if (Array.isArray(parent)) {
      parent.splice(key, 1);
    } else if (typeof parent === 'object' && parent !== null) {
      delete parent[key];
    }
    
    // 删除节点的展开状态记录
    this.expandedState.delete(path);
    
    const originalValue = this.getValueByPath(this.originalJsonData, path);
    if (originalValue !== undefined) {
      this.modifiedValues.set(path, {
        original: originalValue,
        current: undefined,
        status: 'deleted'
      });
    } else {
      this.modifiedValues.delete(path);
    }
  }

  // 修复折叠/展开核心功能
  toggleRow(path) {
    // 获取当前状态并切换
    const currentState = this.expandedState.has(path) ? this.expandedState.get(path) : true;
    this.expandedState.set(path, !currentState);
    
    // 更新UI
    this.renderJsonTable(this.jsonData);
  }

  // 修复全部展开功能
  expandAll() {
    // 递归设置所有节点为展开状态
    this.setAllExpandedState(this.jsonData, '', true);
    this.renderJsonTable(this.jsonData);
  }

  // 修复全部折叠功能
  collapseAll() {
    // 只保留根节点展开，其他都折叠
    this.setAllExpandedState(this.jsonData, '', false);
    // 确保根节点是展开的
    this.expandedState.set('', true);
    this.renderJsonTable(this.jsonData);
  }

  // 递归设置所有节点的展开状态
  setAllExpandedState(json, parentKey = '', state) {
    if (Array.isArray(json)) {
      json.forEach((item, index) => {
        const key = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
        this.expandedState.set(key, state);
        if (typeof item === 'object' && item !== null) {
          this.setAllExpandedState(item, key, state);
        }
      });
    } else if (typeof json === 'object' && json !== null) {
      Object.keys(json).forEach(key => {
        const fullKey = parentKey ? `${parentKey}.${key}` : key;
        this.expandedState.set(fullKey, state);
        if (typeof json[key] === 'object' && json[key] !== null) {
          this.setAllExpandedState(json[key], fullKey, state);
        }
      });
    }
  }

  showTooltip(event, path) {
    const tooltip = document.getElementById('value-tooltip');
    const data = this.modifiedValues.get(path);
    
    if (data) {
      document.getElementById('original-value').textContent = this.formatValue(data.original);
      document.getElementById('current-value').textContent = this.formatValue(data.current);
      
      tooltip.style.left = `${event.pageX + 10}px`;
      tooltip.style.top = `${event.pageY + 10}px`;
      tooltip.classList.add('tooltip-visible');
    }
  }

  hideTooltip() {
    const tooltip = document.getElementById('value-tooltip');
    tooltip.classList.remove('tooltip-visible');
  }
}
